import pluginsImg from '@/assets/image/screenshot/plugins.png';

### 类型定义#definition

```ts
export abstract class PageSpyPlugin {
  /**
   * 每个插件都要求指定 name，会作为当前插件的 "身份标识"。
   * 在 PageSpy 内部的注册插件、禁用插件的功能都依赖 name 属性
   */
  public abstract name: string;

  /**
   * 指定插件加载顺序，插件调用顺序遵循：
   *   1. 插件包含 enforce: "pre" 属性；
   *   2. 插件不包含 enforce 属性；
   *   3. 插件包含 enforce: "post" 属性；
   */
  public abstract enforce?: PluginOrder;

  // new PageSpy() 时调用
  public abstract onInit: (params: OnInitParams) => any;

  // 在 PageSpy 渲染完成后调用（如果有渲染过程的话）
  public abstract onMounted?: (params: OnMountedParams) => any;

  // 当用户不再需要 PageSpy 时，插件应具备 重置/恢复 功能
  public abstract onReset?: () => any;
}

export interface OnInitParams {
  // 已经合并了用户传入的实例化参数的配置信息
  config: Required<InitConfig>;

  // 包装了 socket 实例，插件开发者可以通过该属性与调试端 / API 交互
  socketStore: SocketStoreType;
}

export interface OnMountedParams {
  // PageSpy 渲染的根节点
  root?: HTMLDivElement;

  // PageSpy 渲染的弹窗的根节点
  content?: HTMLDivElement;

  // 包装了 socket 实例，插件开发者可以通过该属性与调试端 / API 交互
  socketStore: SocketStoreType;
}
```

### 行为约定#convention

如果当前插件会收集（或者希望对外公开）平台的某种行为「数据」，那么除了在 `socketStore` 广播数据外，我们约定插件在 `socketStore` 实例上额外派发一个 `"public-data"` 内部事件（Internal Event）。此举的目的是为了满足有统计需求或者持久化需求的插件能够从这个事件中统一收集数据，插件如果觉得某类数据不应该被 “公开”，则无需派发 `"public-data"` 事件。

<img src={pluginsImg} />

### 插件实现案例#demo

参考 [DataHarborPlugin]({VITE_PLUGIN_DATA_HARBOR}) 和 [RRWebPlugin]({VITE_PLUGIN_RRWEB})。

### 插件的使用方式#usage

```html
<!-- 引入 SDK -->
<script src="https://<your-pagespy-host>/page-spy/index.min.js"></script>
<!-- 引入插件 -->
<script src="https://<your-pagespy-host>/plugin/xxx/index.min.js"></script>

<!-- 注册插件 -->
<script>
  PageSpy.registerPlugin(new XXXPlugin());
  window.$pageSpy = new PageSpy();
</script>
```